#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <sys/epoll.h>
#include "log.hpp"
#include "Socket.hpp"

using namespace LogModule;
using namespace SocketModule;

//#define NUM sizeof(fd_set)*8
//#define MAX 4096
const int gdefaultfd = -1;
const int recvs_num = 64;


class EpollServer
{
public:
    EpollServer(uint16_t port)
    :_port(port)
    ,_listen_socket(std::make_unique<TcpSocket>())
    ,_is_running(false)
    {}

    void Init()
    {
        _listen_socket->BuildTcpSocketMethod(_port);
        _epfd = epoll_create(256);
        if(_epfd<0)
        {
            LOG(ERROR)<<"epoll_create error";
            return;
        }
        struct epoll_event ev;
        ev.data.fd = _listen_socket->Fd();
        ev.events = EPOLLIN;
        int n = epoll_ctl(_epfd,EPOLL_CTL_ADD,_listen_socket->Fd(),&ev);
        if(n<0)
        {
            LOG(ERROR)<<"epoll_ctl error";
            return;
        }
    }
    
    void loop()
    {
        fd_set rfds;//读文件描述符集
        _is_running = true;
        while(_is_running)
        {
            int n = epoll_wait(_epfd,_recvs,recvs_num,3000);
            switch (n)
            {
            case 0:
                std::cout<<"time out..."<<std::endl;
                break;
            case -1:
                perror("epoll_wait");
                break;
            default:
                //事件就绪
                //std::cout<<"事件就绪,timeout: "<<timeout.tv_sec<<":"<<timeout.tv_usec<<std::endl;
                Dispatcher(n);
                break;
            }
        }
    }
    //分发任务
    void Dispatcher(int rnum)
    {
        for(int i = 0;i<rnum;++i)
        {
            int fd = _recvs[i].data.fd;
            int events = _recvs[i].events;
            if(fd == gdefaultfd)
                continue;
            if(fd == _listen_socket->Fd())
            {
                if(events & EPOLLIN)
                    Accepter();//获取链接
            }
            else
            {
                if(events & EPOLLIN)
                    Recver(fd);//处理IO
            }
        }
        
    }
    //accept新连接
    void Accepter()
    {
        InetAddr client;
        SockPtr sockp = _listen_socket->Accept(&client);
        if(sockp->Fd()<0)
        {
            perror("accept");
            return;
        }
        else
        {
            int newfd = sockp->Fd();
            std::cout<<"获得新连接,fd:"<<newfd<<std::endl;
            struct epoll_event ev;
            ev.data.fd = newfd;
            ev.events = EPOLLIN;
            int n = epoll_ctl(_epfd,EPOLL_CTL_ADD,newfd,&ev);
            if(n<0)
            {
                perror("epoll_ctl");
                return;
            }
            LOG(DEBUG)<<"epoll_ctl success";
        }
    }
    void Recver(int fd)
    {
        char buffer[1024] = {0};
        int n = recv(fd,buffer,sizeof(buffer)-1,0);//因为文件描述符就绪，所以不会阻塞
        if(n>0)
        {
            std::cout<<"收到消息"<<buffer<<std::endl;
            //读到内容，回传给客户端
            std::string echo("server echo:");
            echo += buffer;
            send(fd,echo.c_str(),echo.size(),0);
        }
        else if(n == 0)
        {
            std::cout<<"client quit,sockfd:"<<fd<<std::endl;
            int n = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr);//先删后关
            if(n<0)
            {
                LOG(ERROR)<<"epoll_ctl error";
                return;
            }
            LOG(DEBUG)<<"epoll success";
            close(fd);
        }
        else
        {
            std::cout<<"recv error,disconnect:"<<fd<<std::endl;
            close(fd);
            int n = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr);//先删后关
            if(n<0)
            {
                LOG(ERROR)<<"epoll_ctl error";
                return;
            }
            LOG(DEBUG)<<"epoll success";
            close(fd);
        }
    }
private:
    uint16_t _port;//端口号
    std::unique_ptr<Socket> _listen_socket;//监听套接字
    bool _is_running;
    int _epfd;
    struct epoll_event _recvs[recvs_num];
};
